#include <iostream>
/*
1. 继承本质和原理
继承的本质： 代码的复用

类与类之间的关系：
组合：a part of ... 一部分的关系
继承：a kind of ... 一种的关系


继承方式及其对应访问权限：
继承方式不修改派生类对基类成员的访问权限，而是修改继承下来的成员在派生类中的访问权限
派生类中的继承成员的访问权限不高于继承方式

默认继承方式：
class定义的派生类，默认继承方式为private
struct定义的派生类，默认继承方式为public

2. 派生类构造和析构过程
父类成员 通过调用父类 构造 函数来初始化（只能在初始化列表中调用,
不能在函数体内部调用） 父类成员 通过调用父类 析构
函数来析构（子类析构函数末尾会自动调用父类析构函数）


3. 函数重载（overload） 函数隐藏 函数覆盖（override）
重载：处在同一个作用域中，函数名字相同，参数列表不同
（在继承关系中，基类和派生类之间的同名函数不具有重载关系，而是隐藏关系）
隐藏：在继承结构中，派生类的同名成员把基类的同名成员给隐藏了
覆盖：基类和派生类的方法，返回值，函数名以及参数列表都相同，而且，基类的方法是虚函数，那么派生类的方法就自动处理为虚函数，它们之间成为覆盖关系
可以用override明确指示方法构成覆盖，让编译器检查是否满足覆盖关系，确保代码没有出错。

4. 基类对象 与 派生类对象 的互相转换
派生类对象转换为基类对象 可以直接转换
基类对象转换为派生类对象 不可以转换！！！

5. 虚函数 静态绑定 动态绑定
一个类如果定义了虚函数，那么编译阶段，编译器给这个类类型产生一个唯一的vftable虚函数表，虚函数表中，虚函数表中主要存储的内容是RTTI指针和
虚函数的地址。 程序运行时，每一张虚函数表都会加载到内存的.rodata区

含有虚函数的类的实例对象都会额外占用4字节的空间，用于存放vfptr虚表指针，虚表指针用于指向虚函数表。
一个类的多个对象，他们的vfptr都是指向同一张虚函数表。

一个类里面虚函数的个数，不影响对象内存大小，影响的是虚函数表的大小。

派生类的方法与基类中的方法构成覆盖（返回值 函数名 参数列表都相同，该基类方法为虚函数）则，
派生类的这个方法 自动处理为虚函数。




 */

#if 0
class Base {
public:
    int ma;

protected:
    int mb;

private:
    int mc;
};

class Derived : public Base {
public:
    int md;

protected:
    int me;

private:
    int mf;
};

class Base {
public:
    Base(int data = 10) : a(data) {
    }
    void show() {
        std::cout << "Base::show()" << std::endl;
    }
    void show(int) {
        std::cout << "Base::show(int)" << std::endl;
    }

private:
    int a;
};

class Derived : public Base {
public:
    Derived(int data = 20) : Base(data), b(data) {
    }

    void show() {
        std::cout << "Derived::show()" << std::endl;
    }

private:
    int b;
};
int main() {
    Derived d;
    d.show();
    d.Base::show();
    d.Base::show(10);
    /* d.show(10);  // Too many arguments to function call, expected 0, have 1;
     */
    std::cout << "=======================================" << std::endl;

    Base b;
    Derived d1;
    Derived d2;
    b = d1;
    b.show();

    /* d2 = b; //  将基类赋值给（转换为）派生类 不可以！ */

    Base* pb = new Derived;
    pb->show();
    delete pb;

    /* Derived* pd = new Base; // 不可以将派生类指针指向基类对象 */
}
#endif
